
#include "Engine.h"
#include "ComponentManager.h"

#include <iostream>
using namespace std;
//#define SHOWFPS


CEngine::CEngine(void):m_running(false), m_screen(0), m_screenWidth(0), m_screenHeight(0), m_screenDepth(0),
m_fps(0), m_fpsTicks(0), m_fpsCounter(0), m_lastTick(0){}

CEngine::~CEngine(void)
{
	SDL_Quit();
}

void CEngine::init(void)
{
	//initialise the console logger
	if(!CM.initLogger("LOG_Console"))
	{
		CM.close();
		exit(1);
	}

	//initialise SDL
#ifdef _WIN
	if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO)==0)
		CM.LOGCONSOLE().Log()<<"LOG : ENGINE : SDL initialised\n";
	else
	{
		CM.LOGCONSOLE().Log()<<"LOG : ENGINE : ERROR : SDL not initialised\n";
		CM.close();
		exit(1);
	}
#endif

#ifdef _GP2X
	if(SDL_Init(SDL_INIT_JOYSTICK | SDL_INIT_VIDEO | SDL_INIT_AUDIO)==0)
	{
		CM.LOGCONSOLE().Log()<<"LOG : ENGINE : SDL initialised\n";
	}
	else
	{
		CM.LOGCONSOLE().Log()<<"LOG : ENGINE : ERROR : SDL not initialised\n";
		system("pause");
		CM.close();
		exit(1);
	}
#endif
		
	//initialise the visualisation component
	if(!CM.initVisualisationComponent("SDL_Visualisation"))
	{
		system("pause");
		CM.close();
		exit(1);
	}

	//initialise the audio component
	if(!CM.initAudioComponent("SDL_Audio"))
	{
		system("pause");
		CM.close();
		exit(1);
	}

	//initialise the user interface component
	string uiComponentName;

#ifdef _WIN
	uiComponentName="WINDOWS_UInterface";
#endif
#ifdef _GP2X
	uiComponentName="GP2X_UInterface";
#endif

	if(!CM.initUIComponent(uiComponentName))
	{
		system("pause");
		CM.close();
		exit(1);
	}

	//initialise the world model component
	if(!CM.initWorldModelComponent("STANDARD_WorldModel"))
	{
		system("pause");
		CM.close();
		exit(1);
	}

	//initialise the scene manager
	if(!CM.initSceneManager("STANDARD_SceneManager"))
	{
		system("pause");
		CM.close();
		exit(1);
	}

	//initialise the projectile manager
	if(!CM.initProjectileManager("STANDARD_ProjectileManager"))
	{
		system("pause");
		CM.close();
		exit(1);
	}

#ifdef _DEBUG 
#ifdef _WIN
	if(!CM.initProfiler("Profiler_WIN"))
	{
		system("pause");
		CM.close();
		exit(1);
	}
	if(!CM.PROFILER().init())
	{
		CM.LOGCONSOLE().Log()<<"LOG : ENGINE : Cannot get the processor frequency!\n";
	}
#endif

#ifdef _GP2X
	if(!CM.initProfiler("Profiler_GP2X"))
	{
		system("pause");
		CM.close();
		exit(1);
	}
#endif
#endif

	if(!CM.initExplosionManager("STANDARD_ExplosionManager"))
	{
		system("pause");
		CM.close();
		exit(1);
	}

	if(!CM.initFileManager("STANDARD_FileManager"))
	{
		system("pause");
		CM.close();
		exit(1);
	}
	
}
void CEngine::load(void)
{
#ifdef _DEBUG
	CM.PROFILER().startApplication();
#endif

#ifdef _DEBUG
	CM.PROFILER().startCount("Load File");
#endif
	if(!CM.FILE().loadFile("./data/zipData.zpak"))
	{
		CM.LOGCONSOLE().Log()<<"ERROR : Can't open the pak file\n";
		system("pause");
		CM.close();
		exit(1);
	}
	
#ifdef _DEBUG
	CM.PROFILER().endCount("Load File");
#endif

	
	int indexSplashScreen;
	if(!CM.VISU().loadTextureFromMemory(&indexSplashScreen, "splashScreen.bmp", 0, 0, 0, 0))
	{
		system("pause");
		CM.close();
		exit(1);
	}


	//splash screen
	int timeToDisplaySplashScreen = 2000;
	int startTimeSplashScreen = SDL_GetTicks();

	while((int)SDL_GetTicks()<startTimeSplashScreen+timeToDisplaySplashScreen)
	{
		CM.VISU().preRender();
		CM.VISU().displayTexture(indexSplashScreen, CVector2i(0, 0));
		CM.VISU().postRender();
	}

	//hide the cursor
	SDL_ShowCursor(0);

	int idTextureIdleRight;
	int idTextureIdleLeft;
	int idTexturePlayerWalk;
	int idTexturePlayerJump;
	int indexBlock;
	int indexBlock2;
	int indexProjectile;
	int idTexturePauseScreen;
	int idTextureEnemy2Walk;

	if(!CM.VISU().loadTextureFromMemory(&idTextureIdleRight, "megaman.bmp", 45, 39, 1, 1))
	{
		system("pause");
		CM.close();
		exit(1);
	}

	if(!CM.VISU().loadTextureFromMemory(&idTextureEnemy2Walk, "enemy2Walk.bmp", 135, 110, 22, 3))
	{
		system("pause");
		CM.close();
		exit(1);
	}

	
	if(!CM.VISU().loadTextureFromMemory(&idTextureIdleLeft, "megaman2.bmp", 45, 39, 1, 1))
	{
		system("pause");
		CM.close();
		exit(1);
	}
	if(!CM.VISU().loadTextureFromMemory(&idTexturePlayerWalk, "playerWalk.bmp", 47, 37, 20, 5))
	{
		system("pause");
		CM.close();
		exit(1);
	}
	if(!CM.VISU().loadTextureFromMemory(&idTexturePlayerJump, "playerJump.bmp", 31, 53, 16, 8))
	{
		system("pause");
		CM.close();
		exit(1);
	}
	if(!CM.VISU().loadTextureFromMemory(&indexBlock, "block.bmp", 0, 0, 0, 0))
	{
		system("pause");
		CM.close();
		exit(1);
	}

	if(!CM.VISU().loadTextureFromMemory(&indexBlock2, "block2.bmp", 0, 0, 0, 0))
	{
		system("pause");
		CM.close();
		exit(1);
	}

	if(!CM.VISU().loadTextureFromMemory(&indexProjectile, "projectile.bmp", 15, 15, 2, 2))
	{
		system("pause");
		CM.close();
		exit(1);
	}

	int indexTextureEnemyWalk;
	if(!CM.VISU().loadTextureFromMemory(&indexTextureEnemyWalk, "enemyWalk.bmp", 62, 66, 14, 5))
	{
		system("pause");
		CM.close();
		exit(1);
	}
	int indexTextureExplosionProjectile;
	if(!CM.VISU().loadTextureFromMemory(&indexTextureExplosionProjectile, "explosionProjectile.bmp", 11, 11, 7, 7))
	{
		system("pause");
		CM.close();
		exit(1);
	}
	int indexTextureExplosionEnemy;
	if(!CM.VISU().loadTextureFromMemory(&indexTextureExplosionEnemy, "explosionEnemy.bmp", 47, 47, 7, 4))
	{
		system("pause");
		CM.close();
		exit(1);
	}
	if(!CM.VISU().loadTextureFromMemory(&idTexturePauseScreen, "pauseScreen.bmp", 0, 0, 0, 0))
	{
		system("pause");
		CM.close();
		exit(1);
	}
	
	//load the sounds
	int enemyExplosionSound;
	if(!CM.AUDIO().loadSoundFromMemory(&enemyExplosionSound, "explosionEnemy.wav"))
	{
		system("pause");
		CM.close();
		exit(1);
	}

	int projectileExplosionSound;
	if(!CM.AUDIO().loadSoundFromMemory(&projectileExplosionSound, "impact.wav"))
	{
		system("pause");
		CM.close();
		exit(1);
	}

	////load fonts
	int idFontHUD=0;
	if(!CM.VISU().loadFontFromMemory(&idFontHUD, "font.bmp", 24, 24, 36, 20))
	{
		system("pause");
		CM.close();
		exit(1);
	}

	//closes all the files to save memory
	CM.FILE().closeFiles();

	int idAnimWalkRight;
	CM.VISU().loadAnimation(&idAnimWalkRight, idTexturePlayerWalk, 0, 9, 100);
	int idAnimWalkLeft;
	CM.VISU().loadAnimation(&idAnimWalkLeft, idTexturePlayerWalk, 10, 19, 100);
	int idAnimIdleRight;
	CM.VISU().loadAnimation(&idAnimIdleRight, idTextureIdleRight, 0, 0, 1000);
	int idAnimIdleLeft;
	CM.VISU().loadAnimation(&idAnimIdleLeft, idTextureIdleLeft, 0, 0, 1000);
	int idAnimJumpLeft;
	CM.VISU().loadAnimation(&idAnimJumpLeft, idTexturePlayerJump, 8, 15, 125);
	int idAnimJumpRight;
	CM.VISU().loadAnimation(&idAnimJumpRight, idTexturePlayerJump, 0, 7, 125);
	int idAnimEnemyWalkRight;
	CM.VISU().loadAnimation(&idAnimEnemyWalkRight, indexTextureEnemyWalk, 0, 6, 200);
	int idAnimEnemyWalkLeft;
	CM.VISU().loadAnimation(&idAnimEnemyWalkLeft, indexTextureEnemyWalk, 7, 13, 200);
	int idAnimExplosionProjectile;
	CM.VISU().loadAnimation(&idAnimExplosionProjectile, indexTextureExplosionProjectile, 0, 6, 75);
	int idAnimExplosionEnemy;
	CM.VISU().loadAnimation(&idAnimExplosionEnemy, indexTextureExplosionEnemy, 0, 6, 75);
	int idAnimEnemy2WalkLeft;
	CM.VISU().loadAnimation(&idAnimEnemy2WalkLeft, idTextureEnemy2Walk, 0, 11, 75);
	int idAnimEnemy2WalkRight;
	CM.VISU().loadAnimation(&idAnimEnemy2WalkRight, idTextureEnemy2Walk, 12, 21, 75);
	

	CM.PROJECTILE().init();
	CM.PROJECTILE().createProjectileType(ePlayerProjectile, indexProjectile, 0, 10, 2, 10);
	CM.PROJECTILE().createProjectileType(eEnemyProjectile, indexProjectile, 1, 20, 2, 10);

	CM.EXPLOSION().init();
	CM.EXPLOSION().createExplosionType(eProjectileExplosion, idAnimExplosionProjectile, projectileExplosionSound);
	CM.EXPLOSION().createExplosionType(eEnemyExplosion, idAnimExplosionEnemy, enemyExplosionSound);
	
	CM.WORLD().setPauseScreen(idTexturePauseScreen);
	//create  entities
	CM.WORLD().createEntityPlayer(CVector2i(0, 0), 6, idAnimWalkRight, idAnimWalkLeft, idAnimIdleRight, idAnimIdleLeft,
		idAnimJumpRight, idAnimJumpLeft, 0, 0, 100);


	CM.WORLD().createEntityDecor(indexBlock, CVector2i(300, 150));	
	CM.WORLD().createEntityDecor(indexBlock, CVector2i(0, 20));		
	CM.WORLD().createEntityDecor(indexBlock2, CVector2i(60, 200));

	CM.WORLD().createEntityDecor(indexBlock2, CVector2i(400, 300));//400
	CM.WORLD().createEntityDecor(indexBlock2, CVector2i(639, 300));

	CM.WORLD().createEntityDecor(indexBlock, CVector2i(880, 250));
	CM.WORLD().createEntityDecor(indexBlock, CVector2i(940, 200));
	CM.WORLD().createEntityDecor(indexBlock, CVector2i(1000, 150));

	CM.WORLD().createEntityDecor(indexBlock, CVector2i(1060, 150));
	CM.WORLD().createEntityDecor(indexBlock, CVector2i(1120, 200));
	CM.WORLD().createEntityDecor(indexBlock, CVector2i(1180, 250));

	CM.WORLD().createEntityDecor(indexBlock2, CVector2i(1250, 300));
	CM.WORLD().createEntityDecor(indexBlock2, CVector2i(1500, 300));
	CM.WORLD().createEntityDecor(indexBlock, CVector2i(1780, 250));
	CM.WORLD().createEntityDecor(indexBlock, CVector2i(1840, 200));
	CM.WORLD().createEntityDecor(indexBlock, CVector2i(1900, 150));
	CM.WORLD().createEntityDecor(indexBlock, CVector2i(1960, 100));
	CM.WORLD().createEntityDecor(indexBlock2, CVector2i(2030, 100));
	CM.WORLD().createEntityDecor(indexBlock2, CVector2i(2270, 100));

	CM.WORLD().createEntityDecor(indexBlock, CVector2i(2510, 50));
	CM.WORLD().createEntityDecor(indexBlock, CVector2i(2570, 100));
	CM.WORLD().createEntityDecor(indexBlock, CVector2i(2630, 150));
	CM.WORLD().createEntityDecor(indexBlock, CVector2i(2690, 100));
	CM.WORLD().createEntityDecor(indexBlock, CVector2i(2750, 50));
	CM.WORLD().createEntityDecor(indexBlock, CVector2i(2810, 100));
	CM.WORLD().createEntityDecor(indexBlock, CVector2i(2870, 150));

	CM.WORLD().createEntityDecor(indexBlock2, CVector2i(2930, 150));
	CM.WORLD().createEntityDecor(indexBlock, CVector2i(3170, 0));


	CM.WORLD().createEntityEnemy(CVector2i(120, 30), 40, idAnimEnemyWalkLeft, idAnimEnemyWalkRight, 100, 1, 2);
	CM.WORLD().createEntityEnemy(CVector2i(500, 200), 50, idAnimEnemyWalkLeft, idAnimEnemyWalkRight, 100, 1, 2);

	CM.WORLD().createEntityEnemy(CVector2i(600, 350), 50, idAnimEnemy2WalkLeft, idAnimEnemy2WalkRight, 100, 10, 2);
	CM.WORLD().createEntityEnemy(CVector2i(1320, 350), 50, idAnimEnemy2WalkLeft, idAnimEnemy2WalkRight, 100, 10, 2);
	CM.WORLD().createEntityEnemy(CVector2i(1520, 350), 50, idAnimEnemy2WalkLeft, idAnimEnemy2WalkRight, 100, 10, 2);

	CM.WORLD().createEntityEnemy(CVector2i(2250, 0), 100, idAnimEnemy2WalkLeft, idAnimEnemy2WalkRight, 100, 10, 2);

	CM.WORLD().createEntityEnemy(CVector2i(3030, -50), 40, idAnimEnemyWalkLeft, idAnimEnemyWalkRight, 100, 1, 2);

	CM.PROJECTILE().createProjectiles(10);
	CM.EXPLOSION().createExplosions(10);


	//create the graph that represent the world
	int depth = 2;
	CM.SCENE().initialiseQuadTree(depth);
	CM.WORLD().fillQuadTree();
	CM.WORLD().scrollWorld(CVector2i(100, 100));

#ifdef _DEBUG
		CM.PROFILER().endApplication();
		CM.PROFILER().write();
#endif
}

void CEngine::start(void)
{


	CM.LOGCONSOLE().Log()<<"LOG : ENGINE : Start Engine\n";

	const int tick=50;
	int currentTickTime=SDL_GetTicks();

	while(!CM.WORLD().quitGame())//while we don't want to quit the game
	{
		
		if(currentTickTime+tick<(int)SDL_GetTicks()) //tick
		{
#ifdef _DEBUG
			CM.PROFILER().startCount("Input Update");
#endif
			CM.UI().inputDoUpdate();
#ifdef _DEBUG
			CM.PROFILER().endCount("Input Update");
#endif

#ifdef _DEBUG
			CM.PROFILER().startCount("WorldModel Update");
#endif
			CM.WORLD().doUpdate();
#ifdef _DEBUG
			CM.PROFILER().endCount("WorldModel Update");
#endif
			currentTickTime=SDL_GetTicks();
		}

#ifdef SHOWFPS
		m_fpsTicks=SDL_GetTicks()-m_lastTick;
		if(m_fpsTicks>1000)
		{
			m_fps=m_fpsCounter;
			m_lastTick=SDL_GetTicks();
			m_fpsCounter=0;
		}
		m_fpsCounter++;
		//char* buffer = new char[255];

		
		//string stringFPS("FPS : ");
		CM.LOGCONSOLE().Log()<<"LOG : FPS = "<<m_fps<<"\n";
		//stringFPS.append(buffer);
		//SetConsoleTitle(stringFPS.c_str());
#endif
		
#ifdef _DEBUG
		CM.PROFILER().startCount("WorldModel Render");
#endif
		doRender();
#ifdef _DEBUG
		CM.PROFILER().endCount("WorldModel Render");
#endif
	}


}

void CEngine::quit(void)
{
	CM.close();
}

void CEngine::doRender(void)
{
	CM.VISU().preRender();

	CM.WORLD().doRender();

	CM.VISU().postRender();

}

